library(modplots)
library(tidyverse)
── Attaching core tidyverse packages ───────────────────────────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     
── Conflicts ─────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(Seurat)
Loading required package: SeuratObject
Loading required package: sp

Attaching package: ‘SeuratObject’

The following objects are masked from ‘package:base’:

    intersect, t
library(plotly)

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
# Mitochondrial genes
mt <- c("ENSGALG00000035334", #COX3
        "ENSGALG00000032456", #COII
        "ENSGALG00000032142", #MT-CO1
        "ENSGALG00000032079", #MT-CYB
        "ENSGALG00000037838", #ND6
        "ENSGALG00000029500", #ND5
        "ENSGALG00000036229", #MT-ND4
        "ENSGALG00000042478", #ND4L
        "ENSGALG00000030436", #ND3
        "ENSGALG00000041091", #MT-ATP6
        "ENSGALG00000032465", #MT-ATP8
        "ENSGALG00000043768", #MT-ND2
        "ENSGALG00000042750") #MT-ND1

# volcanoplot thresholds
p.adj <- 0.05
l2fc <- 0.5

B10-L10-int

# seurat object
my.se <- readRDS("~/spinal_cord_paper/data/Gg_ctrl_lumb_int_seurat_250723.rds")
# cluster labels from B10int and L10int
ctrl_lumb_int_combined_labels <- readRDS("~/spinal_cord_paper/annotations/ctrl_lumb_int_combined_labels.rds")

identical(colnames(my.se), rownames(ctrl_lumb_int_combined_labels))
[1] TRUE
my.se$annot_sample  <- ctrl_lumb_int_combined_labels$annot_sample

my.se@active.assay <- "RNA"

intra cluster DE analysis

We do DE analysis per cluster, contrasting B10 and L10 samples:

markers <- list()
numbers <- list()
composition <-list()

for (i in seq(levels(Idents(my.se)))) {
  # subset for individual clusters
  mn.se <- subset(x = my.se, idents = levels(Idents(my.se))[i])
  mn.se$sample <- str_extract(mn.se$orig.ident, "ctrl|lumb")
  
  composition[[i]] <- mn.se[[]] %>% 
    select(sample, annot_sample)
  
  Idents(mn.se) <- "sample"
  
  tmp_markers <- FindMarkers(mn.se,
                             ident.1 = "ctrl",
                             only.pos = FALSE, 
                             min.pct = 0.25, 
                             logfc.threshold =  0.2,
                             latent.vars = c("CC.Difference.seurat"), 
                             test.use = "MAST", 
                             assay = "RNA")
  # cell numbers per sample
  numbers[[i]] <- data.frame(table(mn.se$sample))
  
  tmp_markers <- tmp_markers %>%
    rownames_to_column("Gene.stable.ID") %>% 
    left_join(gnames)
  
  markers[[i]] <- tmp_markers
}

names(markers) <- paste0("cl-", levels(Idents(my.se)))
names(numbers) <- paste0("cl-", levels(Idents(my.se)))
names(composition) <- paste0("cl-", levels(Idents(my.se)))

# bind lists into data frames
lumb_markers <- bind_rows(markers, .id = "cluster") %>% 
  mutate(cluster = factor(cluster, levels = paste0("cl-", levels(Idents(my.se)))))
lumb_numbers <- bind_rows(numbers, .id = "cluster") %>% 
  mutate(cluster = factor(cluster, levels = paste0("cl-", levels(Idents(my.se)))))
lumb_composition <- bind_rows(composition, .id = "cluster") %>% 
  mutate(cluster = factor(cluster, levels = paste0("cl-", levels(Idents(my.se)))))

saveRDS(lumb_markers, "~/spinal_cord_paper/data/Gg_ctrl_lumb_int_markers.rds")
saveRDS(lumb_numbers, "~/spinal_cord_paper/data/Gg_ctrl_lumb_int_numbers.rds")
saveRDS(lumb_composition, "~/spinal_cord_paper/data/Gg_ctrl_lumb_int_composition.rds")
lumb_markers <- readRDS("~/spinal_cord_paper/data/Gg_ctrl_lumb_int_markers.rds") %>% 
  mutate(clust_id = str_remove(cluster, "^cl-"))
Error in readRDS("~/spinal_cord_paper/data/Gg_ctrl_lumb_int_markers.rds") %>%  : 
  could not find function "%>%"

Plot the cluster compositions and the number of marker genes.


DimPlot(my.se, label = TRUE, reduction = "tsne")


ggplot(data = lumb_numbers, aes(x = Var1, y = Freq, group = cluster, label = Freq)) +
  geom_col() +
  facet_wrap("cluster", nrow = 3) +
  geom_text(nudge_y = 50, size = 3) +
  ggtitle("Cluster composition by sample (nCells)")


ggplot(data = lumb_markers %>% filter(p_val_adj < 0.05 & avg_log2FC > 0.5), aes(x = cluster, group = cluster)) +
  geom_bar() +
  facet_wrap("cluster", nrow = 3,scales = "free_x") +
  ggtitle("Number of sig. DE genes")

NA
NA
NA

DA clusters from miloR

We select the clusters with the highest amount of neighbourhoods with DA of cells. Those are clusters 3 (neurons), 21, 22 (Glycogen body), and 30 motor neurons.

# vector of clusters
select_clusters <- c(3,21,22,30)

select_lumb_markers <- filter(lumb_markers, clust_id %in% select_clusters)
select_lumb_numbers <- filter(lumb_numbers, clust_id %in% select_clusters)
select_lumb_composition <- filter(lumb_composition, clust_id %in% select_clusters)

Barplots

Barplots showing number of cells from B10 or L10, and the contributions from the individual B10int and L10int clusters:

ggplot(data = select_lumb_numbers, aes(x = Var1, y = Freq, group = cluster, label = Freq)) +
  geom_col() +
  facet_wrap("cluster", nrow = 1) +
  geom_text(nudge_y = 10) +
  ggtitle("Cluster composition by sample (nCells)")

toplot <- select_lumb_composition %>% 
  mutate(annot_sample = str_extract(annot_sample, "\\d{1,2}_.{1}(?=trl|umb)")) %>% 
  mutate(annot_sample = factor(annot_sample)) %>% 
  group_by(sample, cluster) %>%
  count(annot_sample) %>% 
  mutate(label_ypos = cumsum(n)- 0.5*n)

BL_select_barplot <- ggplot(data=toplot, aes(x=sample, y=n, fill=fct_rev(annot_sample))) +
  geom_bar(stat="identity", color = "black") +
  geom_text(aes(y=label_ypos, label=annot_sample), 
            color="black", size=3.5) +
  facet_wrap("cluster", nrow = 1) +
    theme(legend.position="none") +
  ggtitle("BL10int cluster contributions")

BL_select_barplot

pdf("~/spinal_cord_paper/figures/Fig_4_BL10int_high_DA_clust_contribution.pdf")
BL_select_barplot
dev.off()
png 
  2 

Volcanoplots

toplot <- select_lumb_markers %>% 
  mutate(gene_type = case_when(
    avg_log2FC >= 0.5 & p_val_adj <= 0.05 ~ "ctrl",
    avg_log2FC <= -0.5 & p_val_adj <= 0.05 ~ "lumb",
    TRUE ~ "ns")
  )

cols <- c(ctrl = "black",
          lumb = "#419c73",
          ns = "grey")

shapes <- c(ctrl = 21,
            lumb = 21,
            ns = 20)

volplot <- ggplot(data = toplot,
                  aes(x = avg_log2FC,
                      y = -log10(p_val_adj),
                      label = Gene.name,
                      color = gene_type,
                      shape = gene_type
                  )) +
  geom_point() +
  geom_hline(yintercept = -log10(p.adj), linetype = "dashed") +
  geom_vline(xintercept = c(-l2fc,l2fc), linetype = "dashed") +
  scale_color_manual(values = cols) +
  scale_shape_manual(values = shapes) +
  facet_wrap("cluster", nrow = 1) +
  ylab("-log10(padj)") +
  theme_bw()+
  ggtitle("Sig. marker genes")

volplot

# ggplotly(volplot, width = 1000, height = 600)

Plots without HOX and mitochondrial genes:

# filter out HOX and MT genes
toplot_nomt <- toplot %>% 
  filter(!grepl("^HOX", Gene.name)) %>% 
  filter(!Gene.stable.ID %in% mt)

volplot_nomt <- ggplot(data = toplot_nomt,
                  aes(x = avg_log2FC,
                      y = -log10(p_val_adj),
                      label = Gene.name,
                      color = gene_type,
                      shape = gene_type
                  )) +
  geom_point() +
  geom_hline(yintercept = -log10(p.adj), linetype = "dashed") +
  geom_vline(xintercept = c(-l2fc,l2fc), linetype = "dashed") +
  scale_color_manual(values = cols) +
  scale_shape_manual(values = shapes) +
  facet_wrap("cluster", nrow = 1) +
  ylab("-log10(padj)") +
  theme_bw()+
  ggtitle("Sig. marker genes (without MT and HOX genes")

volplot_nomt

# ggplotly(volplot_nomt, width = 1000, height = 600)
volplot_nomt +
    ggrepel::geom_text_repel(aes(label = ifelse(gene_type == 'ns',
                                                NA,
                                                Gene.name)),
                             size = 3,
                             color = "black")
Warning: Removed 8233 rows containing missing values or values outside the scale range (`geom_text_repel()`).
Warning: ggrepel: 6 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 208 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 534 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 52 unlabeled data points (too many overlaps). Consider increasing max.overlaps

No MN DE genes

Cluster 30 (Consisting of 161 B10 vs 13 L10 cells) shows no MN related markers. Seemingly, those 13 cells are indeed motor neurons. This is supported by the fact of their expression of TUBB3, FOXP1, and SLC18A3.

# Motor neuron cluster
mn.se <- subset(x = my.se, idents = 30)
mn.se$sample <- str_extract(mn.se$orig.ident, "ctrl|lumb")

mn.se@active.assay <- "integrated"

mn_markers <- gnames[grepl("TUBB3|FOXP1|SLC18A3", gnames$Gene.name),]
mn_markers

VlnPlot(mn.se, group.by = "sample", mn_markers$Gene.stable.ID, cols = c("darkgrey", "#419c73"))

Low DA clusters from miloR

In contrast to the clusters above, we now select clusters 17, 18, and 19. The show a very low amount of DA neighbourhoods, are of similar size and represent neuronal, MFOL, and NPC populations.

# vector of MFOL clusters
low_clusters <- c(17, 18, 19)

low_lumb_markers <- filter(lumb_markers, clust_id %in% low_clusters)
low_lumb_numbers <- filter(lumb_numbers, clust_id %in% low_clusters)
low_lumb_composition <- filter(lumb_composition, clust_id %in% low_clusters)

Barplots

Barplots showing number of cells from B10 or L10, and the contributions from the individual B10int and L10int clusters:

ggplot(data = low_lumb_numbers, aes(x = Var1, y = Freq, group = cluster, label = Freq)) +
  geom_col() +
  facet_wrap("cluster", nrow = 1) +
  geom_text(nudge_y = 10) +
  ggtitle("Cluster composition by sample (nCells)")

toplot <- low_lumb_composition %>% 
  mutate(annot_sample = str_extract(annot_sample, "\\d{1,2}_.{1}(?=trl|umb)")) %>% 
  mutate(annot_sample = factor(annot_sample)) %>% 
  group_by(sample, cluster) %>%
  count(annot_sample) %>% 
  mutate(label_ypos = cumsum(n)- 0.5*n)

BL_low_barplot <- ggplot(data=toplot, aes(x=sample, y=n, fill=fct_rev(annot_sample))) +
  geom_bar(stat="identity", color = "black") +
  geom_text(aes(y=label_ypos, label=annot_sample), 
            color="black", size=3.5) +
  facet_wrap("cluster", nrow = 1) +
    theme(legend.position="none") +
  ggtitle("From which clusters do cells come?")

BL_low_barplot

pdf("~/spinal_cord_paper/figures/Fig_4_BL10int_low_DA_clust_contribution.pdf")
BL_low_barplot
dev.off()
png 
  2 

Volcanoplots

toplot <- low_lumb_markers %>% 
  mutate(gene_type = case_when(
    avg_log2FC >= 0.5 & p_val_adj <= 0.05 ~ "ctrl",
    avg_log2FC <= -0.5 & p_val_adj <= 0.05 ~ "lumb",
    TRUE ~ "ns")
  )

cols <- c(ctrl = "black",
          lumb = "#419c73",
          ns = "grey")

shapes <- c(ctrl = 21,
            lumb = 21,
            ns = 20)

volplot <- ggplot(data = toplot,
                  aes(x = avg_log2FC,
                      y = -log10(p_val_adj),
                      label = Gene.name,
                      color = gene_type,
                      shape = gene_type
                  )) +
  geom_point() +
  geom_hline(yintercept = -log10(p.adj), linetype = "dashed") +
  geom_vline(xintercept = c(-l2fc,l2fc), linetype = "dashed") +
  scale_color_manual(values = cols) +
  scale_shape_manual(values = shapes) +
  xlim(c(-3.5, 3.5)) +
  facet_wrap("cluster", nrow = 1) +
  ylab("-log10(padj)") +
  theme_bw()+
  ggtitle("Sig. marker genes")

volplot

# ggplotly(volplot, width = 800, height = 500)

Plots without HOX and mitochondrial genes:

# filter out HOX and MT genes
toplot_nomt <- toplot %>% 
  filter(!grepl("^HOX", Gene.name)) %>% 
  filter(!Gene.stable.ID %in% mt)

volplot_nomt <- ggplot(data = toplot_nomt,
                  aes(x = avg_log2FC,
                      y = -log10(p_val_adj),
                      label = Gene.name,
                      color = gene_type,
                      shape = gene_type
                  )) +
  geom_point() +
  geom_hline(yintercept = -log10(p.adj), linetype = "dashed") +
  geom_vline(xintercept = c(-l2fc,l2fc), linetype = "dashed") +
  scale_color_manual(values = cols) +
  scale_shape_manual(values = shapes) +
  xlim(c(-1.5, 1.5)) +
  facet_wrap("cluster", nrow = 1, scales = "free_y") +
  ylab("-log10(padj)") +
  theme_bw()+
  ggtitle("Sig. marker genes (without MT and HOX genes)")

volplot_nomt

# ggplotly(volplot_nomt, width = 800, height = 500)
p1 <- volplot +
    ggrepel::geom_text_repel(aes(label = ifelse(gene_type == 'ns',
                                                NA,
                                                Gene.name)),
                             size = 3,
                             color = "black")

p2 <- volplot_nomt +
    ggrepel::geom_text_repel(aes(label = ifelse(gene_type == 'ns',
                                                NA,
                                                Gene.name)),
                             size = 3,
                             color = "black")

p1
Warning: Removed 1289 rows containing missing values or values outside the scale range (`geom_text_repel()`).
Warning: ggrepel: 11 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 15 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 34 unlabeled data points (too many overlaps). Consider increasing max.overlaps

p2
Warning: Removed 1264 rows containing missing values or values outside the scale range (`geom_text_repel()`).
pdf("~/spinal_cord_paper/figures/Fig_4_BL10int_low_DA_volplots.pdf", width = 8, height = 4)
p1
Warning: Removed 1289 rows containing missing values or values outside the scale range (`geom_text_repel()`).
Warning: ggrepel: 12 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 16 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 35 unlabeled data points (too many overlaps). Consider increasing max.overlaps
p2
Warning: Removed 1264 rows containing missing values or values outside the scale range (`geom_text_repel()`).
Warning: ggrepel: 1 unlabeled data points (too many overlaps). Consider increasing max.overlaps
dev.off()
png 
  2 

B10-P10-int

# seurat object
my.se <- readRDS("~/spinal_cord_paper/data/Gg_ctrl_poly_int_seurat_250723.rds")
# cluster labels from B10int and L10int
ctrl_poly_int_combined_labels <- readRDS("~/spinal_cord_paper/annotations/ctrl_poly_int_combined_labels.rds")

identical(colnames(my.se), rownames(ctrl_poly_int_combined_labels))
[1] TRUE
my.se$annot_sample  <- ctrl_poly_int_combined_labels$annot_sample

my.se@active.assay <- "RNA"

intra cluster DE analysis

We do DE analysis per cluster, contrasting B10 and P10 samples:

markers <- list()
numbers <- list()
composition <- list()

for (i in seq(levels(Idents(my.se)))) {
  # subset for individual clusters
  mn.se <- subset(x = my.se, idents = levels(Idents(my.se))[i])
  mn.se$sample <- str_extract(mn.se$orig.ident, "ctrl|poly")
  
  composition[[i]] <- mn.se[[]] %>% 
    select(sample, annot_sample)
  
  Idents(mn.se) <- "sample"
  
  tmp_markers <- FindMarkers(mn.se,
                             ident.1 = "ctrl",
                             only.pos = FALSE, 
                             min.pct = 0.25, 
                             logfc.threshold =  0.2,
                             latent.vars = c("CC.Difference.seurat"), 
                             test.use = "MAST", 
                             assay = "RNA")
  # cell numbers per sample
  numbers[[i]] <- data.frame(table(mn.se$sample))
  
  tmp_markers <- tmp_markers %>%
    rownames_to_column("Gene.stable.ID") %>% 
    left_join(gnames)
  
  
  markers[[i]] <- tmp_markers
}

names(markers) <- paste0("cl-", levels(Idents(my.se)))
names(numbers) <- paste0("cl-", levels(Idents(my.se)))
names(composition) <- paste0("cl-", levels(Idents(my.se)))

# bind lists into data frames
poly_markers <- bind_rows(markers, .id = "cluster") %>% 
  mutate(cluster = factor(cluster, levels = paste0("cl-", levels(Idents(my.se)))))
poly_numbers <- bind_rows(numbers, .id = "cluster") %>% 
  mutate(cluster = factor(cluster, levels = paste0("cl-", levels(Idents(my.se)))))
poly_composition <- bind_rows(composition, .id = "cluster") %>% 
  mutate(cluster = factor(cluster, levels = paste0("cl-", levels(Idents(my.se)))))

saveRDS(poly_markers, "~/spinal_cord_paper/data/Gg_ctrl_poly_int_markers.rds")
saveRDS(poly_numbers, "~/spinal_cord_paper/data/Gg_ctrl_poly_int_numbers.rds")
saveRDS(poly_composition, "~/spinal_cord_paper/data/Gg_ctrl_poly_int_composition.rds")
# load the DE data
poly_markers <- readRDS("~/spinal_cord_paper/data/Gg_ctrl_poly_int_markers.rds") %>% 
  mutate(clust_id = str_remove(cluster, "^cl-"))
poly_numbers <- readRDS("~/spinal_cord_paper/data/Gg_ctrl_poly_int_numbers.rds") %>% 
  mutate(clust_id = str_remove(cluster, "^cl-"))
poly_composition <- readRDS("~/spinal_cord_paper/data/Gg_ctrl_poly_int_composition.rds") %>% 
  mutate(clust_id = str_remove(cluster, "^cl-"))

Plot the cluster compositions and the number of marker genes.


DimPlot(my.se, label = TRUE, reduction = "tsne")


ggplot(data = poly_numbers, aes(x = Var1, y = Freq, group = cluster, label = Freq)) +
  geom_col() +
  facet_wrap("cluster", nrow = 3) +
  geom_text(nudge_y = 50, size = 3) +
  ggtitle("Cluster composition by sample (nCells)")


ggplot(data = poly_markers %>% filter(p_val_adj < 0.05 & avg_log2FC > 0.5), aes(x = cluster, group = cluster)) +
  geom_bar() +
  facet_wrap("cluster", nrow = 3,scales = "free_x") +
  ggtitle("Number of sig. DE genes")

Fig5 candidates

# vector of neuronal clusters
fig5_clusters <- c(5,11,18,23,25)

fig5_poly_markers <- filter(poly_markers, clust_id %in% fig5_clusters)
fig5_poly_numbers <- filter(poly_numbers, clust_id %in% fig5_clusters)
fig5_poly_composition <- filter(poly_composition, clust_id %in% fig5_clusters)

Barplots

Barplots showing number of cells from B10 or P10, and the contributions from the individual B10int and P10int clusters:

ggplot(data = fig5_poly_numbers, aes(x = Var1, y = Freq, group = cluster, label = Freq)) +
  geom_col() +
  facet_wrap("cluster", nrow = 1) +
  geom_text(nudge_y = 10) +
  ggtitle("Cluster composition by sample (nCells)")


toplot <- fig5_poly_composition %>% 
  mutate(annot_sample = str_extract(annot_sample, "\\d{1,2}_.{1}(?=trl|oly)")) %>% 
  mutate(annot_sample = factor(annot_sample)) %>% 
  group_by(sample, cluster) %>%
  count(annot_sample) %>% 
  mutate(label_ypos = cumsum(n)- 0.5*n)

BP_neuron_barplot <- ggplot(data=toplot, aes(x=sample, y=n, fill=fct_rev(annot_sample))) +
  geom_bar(stat="identity", color = "black") +
  geom_text(aes(y=label_ypos, label=annot_sample), 
            color="black", size=3.5) +
  facet_wrap("cluster", nrow = 1) + 
    theme(legend.position="none") +
  ggtitle("From which clusters do cells come?")

BP_neuron_barplot 

Volcanoplots

toplot <- fig5_poly_markers %>% 
  mutate(gene_type = case_when(
    avg_log2FC >= 0.5 & p_val_adj <= 0.05 ~ "ctrl",
    avg_log2FC <= -0.5 & p_val_adj <= 0.05 ~ "poly",
    TRUE ~ "ns")
  )

cols <- c(ctrl = "black",
          poly = "goldenrod3",
          ns = "grey")

shapes <- c(ctrl = 21,
            poly = 21,
            ns = 20)


volplot <- ggplot(data = toplot,
                       aes(x = avg_log2FC,
                           y = -log10(p_val_adj),
                           label = Gene.name,
                      color = gene_type,
                      shape = gene_type
                       )) +
  geom_point() +
  geom_hline(yintercept = -log10(p.adj), linetype = "dashed") +
  geom_vline(xintercept = c(-l2fc,l2fc), linetype = "dashed") +
  scale_color_manual(values = cols) +
  scale_shape_manual(values = shapes) +
  facet_wrap("cluster", nrow = 2, scales = "free") +
  ylab("-log10(padj)") +
  theme_bw()+
  ggtitle("Sig. marker genes")

ggplotly(volplot, width = 1000, height = 600)
Warning in dev_fun(filename = tempfile(), width = width %||% 640, height = height %||%  :
  unable to open connection to X11 display ''
Error in .External2(C_X11, paste0("png::", filename), g$width, g$height,  : 
  unable to start device PNG

Plots without mitochondrial genes:

toplot_nomt <- toplot %>% 
  filter(!Gene.stable.ID %in% mt)

volplot_nomt <- ggplot(data = toplot_nomt,
                       aes(x = avg_log2FC,
                           y = -log10(p_val_adj),
                           label = Gene.name,
                      color = gene_type,
                      shape = gene_type
                       )) +
  geom_point() +
  geom_hline(yintercept = -log10(p.adj), linetype = "dashed") +
  geom_vline(xintercept = c(-l2fc,l2fc), linetype = "dashed") +
  scale_color_manual(values = cols) +
  scale_shape_manual(values = shapes) +
  facet_wrap("cluster", nrow = 1) +
  ylab("-log10(padj)") +
  theme_bw()+
  ggtitle("Sig. marker genes (without MT and HOX genes")

ggplotly(volplot_nomt)
Warning in dev_fun(filename = tempfile(), width = width %||% 640, height = height %||%  :
  unable to open connection to X11 display ''
Error in .External2(C_X11, paste0("png::", filename), g$width, g$height,  : 
  unable to start device PNG
pdf("~/spinal_cord_paper/figures/Fig_5_BPoly10int_volplots.pdf", width = 12, height = 4)
pfig5
Warning: Removed 2860 rows containing missing values or values outside the scale range
(`geom_text_repel()`).
Warning: ggrepel: 151 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 6 unlabeled data points (too many overlaps). Consider increasing max.overlaps
dev.off()
null device 
          1 
# Date and time of Rendering
Sys.time()

sessionInfo()
LS0tCnRpdGxlOiAiQjEwLUwxMC1pbnQgYW5kIEIxMC1QMTAtaW50IERFIChuZXVyb25zKSIKYXV0aG9yOiAiRmFiaW8gU2FjaGVyIgpkYXRlOiAiMDMuMDkuMjAyNCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IFRSVUUKICAgIHRvY19mbG9hdDogVFJVRQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgaHRtbF9ub3RlYm9vazoKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogOAplZGl0b3Jfb3B0aW9uczoKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge3IgbGlicmFyaWVzfQpsaWJyYXJ5KG1vZHBsb3RzKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkocGxvdGx5KQpgYGAKCmBgYHtyIHNldHVwfQojIE1pdG9jaG9uZHJpYWwgZ2VuZXMKbXQgPC0gYygiRU5TR0FMRzAwMDAwMDM1MzM0IiwgI0NPWDMKICAgICAgICAiRU5TR0FMRzAwMDAwMDMyNDU2IiwgI0NPSUkKICAgICAgICAiRU5TR0FMRzAwMDAwMDMyMTQyIiwgI01ULUNPMQogICAgICAgICJFTlNHQUxHMDAwMDAwMzIwNzkiLCAjTVQtQ1lCCiAgICAgICAgIkVOU0dBTEcwMDAwMDAzNzgzOCIsICNORDYKICAgICAgICAiRU5TR0FMRzAwMDAwMDI5NTAwIiwgI05ENQogICAgICAgICJFTlNHQUxHMDAwMDAwMzYyMjkiLCAjTVQtTkQ0CiAgICAgICAgIkVOU0dBTEcwMDAwMDA0MjQ3OCIsICNORDRMCiAgICAgICAgIkVOU0dBTEcwMDAwMDAzMDQzNiIsICNORDMKICAgICAgICAiRU5TR0FMRzAwMDAwMDQxMDkxIiwgI01ULUFUUDYKICAgICAgICAiRU5TR0FMRzAwMDAwMDMyNDY1IiwgI01ULUFUUDgKICAgICAgICAiRU5TR0FMRzAwMDAwMDQzNzY4IiwgI01ULU5EMgogICAgICAgICJFTlNHQUxHMDAwMDAwNDI3NTAiKSAjTVQtTkQxCgojIHZvbGNhbm9wbG90IHRocmVzaG9sZHMKcC5hZGogPC0gMC4wNQpsMmZjIDwtIDAuNQpgYGAKCiMgQjEwLUwxMC1pbnQKCmBgYHtyIEIxMC1MMTAtaW50fQojIHNldXJhdCBvYmplY3QKbXkuc2UgPC0gcmVhZFJEUygifi9zcGluYWxfY29yZF9wYXBlci9kYXRhL0dnX2N0cmxfbHVtYl9pbnRfc2V1cmF0XzI1MDcyMy5yZHMiKQojIGNsdXN0ZXIgbGFiZWxzIGZyb20gQjEwaW50IGFuZCBMMTBpbnQKY3RybF9sdW1iX2ludF9jb21iaW5lZF9sYWJlbHMgPC0gcmVhZFJEUygifi9zcGluYWxfY29yZF9wYXBlci9hbm5vdGF0aW9ucy9jdHJsX2x1bWJfaW50X2NvbWJpbmVkX2xhYmVscy5yZHMiKQoKaWRlbnRpY2FsKGNvbG5hbWVzKG15LnNlKSwgcm93bmFtZXMoY3RybF9sdW1iX2ludF9jb21iaW5lZF9sYWJlbHMpKQpteS5zZSRhbm5vdF9zYW1wbGUgIDwtIGN0cmxfbHVtYl9pbnRfY29tYmluZWRfbGFiZWxzJGFubm90X3NhbXBsZQoKbXkuc2VAYWN0aXZlLmFzc2F5IDwtICJSTkEiCgpgYGAKCiMjIGludHJhIGNsdXN0ZXIgREUgYW5hbHlzaXMKCldlIGRvIERFIGFuYWx5c2lzIHBlciBjbHVzdGVyLCBjb250cmFzdGluZyBCMTAgYW5kIEwxMCBzYW1wbGVzOgoKYGBge3IgaW50cmEtY2x1c3Rlci1ERS1MMTAsIGV2YWw9RkFMU0V9Cm1hcmtlcnMgPC0gbGlzdCgpCm51bWJlcnMgPC0gbGlzdCgpCmNvbXBvc2l0aW9uIDwtbGlzdCgpCgpmb3IgKGkgaW4gc2VxKGxldmVscyhJZGVudHMobXkuc2UpKSkpIHsKICAjIHN1YnNldCBmb3IgaW5kaXZpZHVhbCBjbHVzdGVycwogIG1uLnNlIDwtIHN1YnNldCh4ID0gbXkuc2UsIGlkZW50cyA9IGxldmVscyhJZGVudHMobXkuc2UpKVtpXSkKICBtbi5zZSRzYW1wbGUgPC0gc3RyX2V4dHJhY3QobW4uc2Ukb3JpZy5pZGVudCwgImN0cmx8bHVtYiIpCiAgCiAgY29tcG9zaXRpb25bW2ldXSA8LSBtbi5zZVtbXV0gJT4lIAogICAgc2VsZWN0KHNhbXBsZSwgYW5ub3Rfc2FtcGxlKQogIAogIElkZW50cyhtbi5zZSkgPC0gInNhbXBsZSIKICAKICB0bXBfbWFya2VycyA8LSBGaW5kTWFya2Vycyhtbi5zZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZGVudC4xID0gImN0cmwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5wY3QgPSAwLjI1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAgMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhdGVudC52YXJzID0gYygiQ0MuRGlmZmVyZW5jZS5zZXVyYXQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAiTUFTVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlJOQSIpCiAgIyBjZWxsIG51bWJlcnMgcGVyIHNhbXBsZQogIG51bWJlcnNbW2ldXSA8LSBkYXRhLmZyYW1lKHRhYmxlKG1uLnNlJHNhbXBsZSkpCiAgCiAgdG1wX21hcmtlcnMgPC0gdG1wX21hcmtlcnMgJT4lCiAgICByb3duYW1lc190b19jb2x1bW4oIkdlbmUuc3RhYmxlLklEIikgJT4lIAogICAgbGVmdF9qb2luKGduYW1lcykKICAKICBtYXJrZXJzW1tpXV0gPC0gdG1wX21hcmtlcnMKfQoKbmFtZXMobWFya2VycykgPC0gcGFzdGUwKCJjbC0iLCBsZXZlbHMoSWRlbnRzKG15LnNlKSkpCm5hbWVzKG51bWJlcnMpIDwtIHBhc3RlMCgiY2wtIiwgbGV2ZWxzKElkZW50cyhteS5zZSkpKQpuYW1lcyhjb21wb3NpdGlvbikgPC0gcGFzdGUwKCJjbC0iLCBsZXZlbHMoSWRlbnRzKG15LnNlKSkpCgojIGJpbmQgbGlzdHMgaW50byBkYXRhIGZyYW1lcwpsdW1iX21hcmtlcnMgPC0gYmluZF9yb3dzKG1hcmtlcnMsIC5pZCA9ICJjbHVzdGVyIikgJT4lIAogIG11dGF0ZShjbHVzdGVyID0gZmFjdG9yKGNsdXN0ZXIsIGxldmVscyA9IHBhc3RlMCgiY2wtIiwgbGV2ZWxzKElkZW50cyhteS5zZSkpKSkpCmx1bWJfbnVtYmVycyA8LSBiaW5kX3Jvd3MobnVtYmVycywgLmlkID0gImNsdXN0ZXIiKSAlPiUgCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoY2x1c3RlciwgbGV2ZWxzID0gcGFzdGUwKCJjbC0iLCBsZXZlbHMoSWRlbnRzKG15LnNlKSkpKSkKbHVtYl9jb21wb3NpdGlvbiA8LSBiaW5kX3Jvd3MoY29tcG9zaXRpb24sIC5pZCA9ICJjbHVzdGVyIikgJT4lIAogIG11dGF0ZShjbHVzdGVyID0gZmFjdG9yKGNsdXN0ZXIsIGxldmVscyA9IHBhc3RlMCgiY2wtIiwgbGV2ZWxzKElkZW50cyhteS5zZSkpKSkpCgpzYXZlUkRTKGx1bWJfbWFya2VycywgIn4vc3BpbmFsX2NvcmRfcGFwZXIvZGF0YS9HZ19jdHJsX2x1bWJfaW50X21hcmtlcnMucmRzIikKc2F2ZVJEUyhsdW1iX251bWJlcnMsICJ+L3NwaW5hbF9jb3JkX3BhcGVyL2RhdGEvR2dfY3RybF9sdW1iX2ludF9udW1iZXJzLnJkcyIpCnNhdmVSRFMobHVtYl9jb21wb3NpdGlvbiwgIn4vc3BpbmFsX2NvcmRfcGFwZXIvZGF0YS9HZ19jdHJsX2x1bWJfaW50X2NvbXBvc2l0aW9uLnJkcyIpCmBgYAoKYGBge3J9CiMgbG9hZCB0aGUgREUgZGF0YQpsdW1iX21hcmtlcnMgPC0gcmVhZFJEUygifi9zcGluYWxfY29yZF9wYXBlci9kYXRhL0dnX2N0cmxfbHVtYl9pbnRfbWFya2Vycy5yZHMiKSAlPiUgCiAgbXV0YXRlKGNsdXN0X2lkID0gc3RyX3JlbW92ZShjbHVzdGVyLCAiXmNsLSIpKQpsdW1iX251bWJlcnMgPC0gcmVhZFJEUygifi9zcGluYWxfY29yZF9wYXBlci9kYXRhL0dnX2N0cmxfbHVtYl9pbnRfbnVtYmVycy5yZHMiKSAlPiUgCiAgbXV0YXRlKGNsdXN0X2lkID0gc3RyX3JlbW92ZShjbHVzdGVyLCAiXmNsLSIpKQpsdW1iX2NvbXBvc2l0aW9uIDwtIHJlYWRSRFMoIn4vc3BpbmFsX2NvcmRfcGFwZXIvZGF0YS9HZ19jdHJsX2x1bWJfaW50X2NvbXBvc2l0aW9uLnJkcyIpICU+JSAKICBtdXRhdGUoY2x1c3RfaWQgPSBzdHJfcmVtb3ZlKGNsdXN0ZXIsICJeY2wtIikpCmBgYAoKUGxvdCB0aGUgY2x1c3RlciBjb21wb3NpdGlvbnMgYW5kIHRoZSBudW1iZXIgb2YgbWFya2VyIGdlbmVzLgoKYGBge3J9CgpEaW1QbG90KG15LnNlLCBsYWJlbCA9IFRSVUUsIHJlZHVjdGlvbiA9ICJ0c25lIikKCmdncGxvdChkYXRhID0gbHVtYl9udW1iZXJzLCBhZXMoeCA9IFZhcjEsIHkgPSBGcmVxLCBncm91cCA9IGNsdXN0ZXIsIGxhYmVsID0gRnJlcSkpICsKICBnZW9tX2NvbCgpICsKICBmYWNldF93cmFwKCJjbHVzdGVyIiwgbnJvdyA9IDMpICsKICBnZW9tX3RleHQobnVkZ2VfeSA9IDUwLCBzaXplID0gMykgKwogIGdndGl0bGUoIkNsdXN0ZXIgY29tcG9zaXRpb24gYnkgc2FtcGxlIChuQ2VsbHMpIikKCmdncGxvdChkYXRhID0gbHVtYl9tYXJrZXJzICU+JSBmaWx0ZXIocF92YWxfYWRqIDwgMC4wNSAmIGF2Z19sb2cyRkMgPiAwLjUpLCBhZXMoeCA9IGNsdXN0ZXIsIGdyb3VwID0gY2x1c3RlcikpICsKICBnZW9tX2JhcigpICsKICBmYWNldF93cmFwKCJjbHVzdGVyIiwgbnJvdyA9IDMsc2NhbGVzID0gImZyZWVfeCIpICsKICBnZ3RpdGxlKCJOdW1iZXIgb2Ygc2lnLiBERSBnZW5lcyIpCgoKCmBgYAoKIyMgREEgY2x1c3RlcnMgZnJvbSBtaWxvUgoKV2Ugc2VsZWN0IHRoZSBjbHVzdGVycyB3aXRoIHRoZSBoaWdoZXN0IGFtb3VudCBvZiBuZWlnaGJvdXJob29kcyB3aXRoIERBIG9mIGNlbGxzLiBUaG9zZSBhcmUgY2x1c3RlcnMgMyAobmV1cm9ucyksIDIxLCAyMiAoR2x5Y29nZW4gYm9keSksIGFuZCAzMCBtb3RvciBuZXVyb25zLgoKYGBge3J9CiMgdmVjdG9yIG9mIGNsdXN0ZXJzCnNlbGVjdF9jbHVzdGVycyA8LSBjKDMsMjEsMjIsMzApCgpzZWxlY3RfbHVtYl9tYXJrZXJzIDwtIGZpbHRlcihsdW1iX21hcmtlcnMsIGNsdXN0X2lkICVpbiUgc2VsZWN0X2NsdXN0ZXJzKQpzZWxlY3RfbHVtYl9udW1iZXJzIDwtIGZpbHRlcihsdW1iX251bWJlcnMsIGNsdXN0X2lkICVpbiUgc2VsZWN0X2NsdXN0ZXJzKQpzZWxlY3RfbHVtYl9jb21wb3NpdGlvbiA8LSBmaWx0ZXIobHVtYl9jb21wb3NpdGlvbiwgY2x1c3RfaWQgJWluJSBzZWxlY3RfY2x1c3RlcnMpCmBgYAoKCiMjIyBCYXJwbG90cwoKQmFycGxvdHMgc2hvd2luZyBudW1iZXIgb2YgY2VsbHMgZnJvbSBCMTAgb3IgTDEwLCBhbmQgdGhlIGNvbnRyaWJ1dGlvbnMgZnJvbSB0aGUgaW5kaXZpZHVhbCBCMTBpbnQgYW5kIEwxMGludCBjbHVzdGVyczoKCmBgYHtyIGJhcnBsb3RzLUwxMH0KZ2dwbG90KGRhdGEgPSBzZWxlY3RfbHVtYl9udW1iZXJzLCBhZXMoeCA9IFZhcjEsIHkgPSBGcmVxLCBncm91cCA9IGNsdXN0ZXIsIGxhYmVsID0gRnJlcSkpICsKICBnZW9tX2NvbCgpICsKICBmYWNldF93cmFwKCJjbHVzdGVyIiwgbnJvdyA9IDEpICsKICBnZW9tX3RleHQobnVkZ2VfeSA9IDEwKSArCiAgZ2d0aXRsZSgiQ2x1c3RlciBjb21wb3NpdGlvbiBieSBzYW1wbGUgKG5DZWxscykiKQoKYGBgCgpgYGB7cn0KdG9wbG90IDwtIHNlbGVjdF9sdW1iX2NvbXBvc2l0aW9uICU+JSAKICBtdXRhdGUoYW5ub3Rfc2FtcGxlID0gc3RyX2V4dHJhY3QoYW5ub3Rfc2FtcGxlLCAiXFxkezEsMn1fLnsxfSg/PXRybHx1bWIpIikpICU+JSAKICBtdXRhdGUoYW5ub3Rfc2FtcGxlID0gZmFjdG9yKGFubm90X3NhbXBsZSkpICU+JSAKICBncm91cF9ieShzYW1wbGUsIGNsdXN0ZXIpICU+JQogIGNvdW50KGFubm90X3NhbXBsZSkgJT4lIAogIG11dGF0ZShsYWJlbF95cG9zID0gY3Vtc3VtKG4pLSAwLjUqbikKCkJMX3NlbGVjdF9iYXJwbG90IDwtIGdncGxvdChkYXRhPXRvcGxvdCwgYWVzKHg9c2FtcGxlLCB5PW4sIGZpbGw9ZmN0X3Jldihhbm5vdF9zYW1wbGUpKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyh5PWxhYmVsX3lwb3MsIGxhYmVsPWFubm90X3NhbXBsZSksIAogICAgICAgICAgICBjb2xvcj0iYmxhY2siLCBzaXplPTMuNSkgKwogIGZhY2V0X3dyYXAoImNsdXN0ZXIiLCBucm93ID0gMSkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogIGdndGl0bGUoIkJMMTBpbnQgY2x1c3RlciBjb250cmlidXRpb25zIikKCkJMX3NlbGVjdF9iYXJwbG90CgpwZGYoIn4vc3BpbmFsX2NvcmRfcGFwZXIvZmlndXJlcy9GaWdfNF9CTDEwaW50X2hpZ2hfREFfY2x1c3RfY29udHJpYnV0aW9uLnBkZiIpCkJMX3NlbGVjdF9iYXJwbG90CmRldi5vZmYoKQoKYGBgCgoKIyMjIFZvbGNhbm9wbG90cwoKYGBge3Igdm9scGxvdHMtTDEwLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDZ9CnRvcGxvdCA8LSBzZWxlY3RfbHVtYl9tYXJrZXJzICU+JSAKICBtdXRhdGUoZ2VuZV90eXBlID0gY2FzZV93aGVuKAogICAgYXZnX2xvZzJGQyA+PSAwLjUgJiBwX3ZhbF9hZGogPD0gMC4wNSB+ICJjdHJsIiwKICAgIGF2Z19sb2cyRkMgPD0gLTAuNSAmIHBfdmFsX2FkaiA8PSAwLjA1IH4gImx1bWIiLAogICAgVFJVRSB+ICJucyIpCiAgKQoKY29scyA8LSBjKGN0cmwgPSAiYmxhY2siLAogICAgICAgICAgbHVtYiA9ICIjNDE5YzczIiwKICAgICAgICAgIG5zID0gImdyZXkiKQoKc2hhcGVzIDwtIGMoY3RybCA9IDIxLAogICAgICAgICAgICBsdW1iID0gMjEsCiAgICAgICAgICAgIG5zID0gMjApCgp2b2xwbG90IDwtIGdncGxvdChkYXRhID0gdG9wbG90LAogICAgICAgICAgICAgICAgICBhZXMoeCA9IGF2Z19sb2cyRkMsCiAgICAgICAgICAgICAgICAgICAgICB5ID0gLWxvZzEwKHBfdmFsX2FkaiksCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IEdlbmUubmFtZSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gZ2VuZV90eXBlLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBnZW5lX3R5cGUKICAgICAgICAgICAgICAgICAgKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKHAuYWRqKSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLWwyZmMsbDJmYyksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29scykgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBzaGFwZXMpICsKICBmYWNldF93cmFwKCJjbHVzdGVyIiwgbnJvdyA9IDEpICsKICB5bGFiKCItbG9nMTAocGFkaikiKSArCiAgdGhlbWVfYncoKSsKICBnZ3RpdGxlKCJTaWcuIG1hcmtlciBnZW5lcyIpCgp2b2xwbG90CiMgZ2dwbG90bHkodm9scGxvdCwgd2lkdGggPSAxMDAwLCBoZWlnaHQgPSA2MDApCgpgYGAKClBsb3RzIHdpdGhvdXQgSE9YIGFuZCBtaXRvY2hvbmRyaWFsIGdlbmVzOgoKYGBge3IsICBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDZ9CiMgZmlsdGVyIG91dCBIT1ggYW5kIE1UIGdlbmVzCnRvcGxvdF9ub210IDwtIHRvcGxvdCAlPiUgCiAgZmlsdGVyKCFncmVwbCgiXkhPWCIsIEdlbmUubmFtZSkpICU+JSAKICBmaWx0ZXIoIUdlbmUuc3RhYmxlLklEICVpbiUgbXQpCgp2b2xwbG90X25vbXQgPC0gZ2dwbG90KGRhdGEgPSB0b3Bsb3Rfbm9tdCwKICAgICAgICAgICAgICAgICAgYWVzKHggPSBhdmdfbG9nMkZDLAogICAgICAgICAgICAgICAgICAgICAgeSA9IC1sb2cxMChwX3ZhbF9hZGopLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBHZW5lLm5hbWUsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGdlbmVfdHlwZSwKICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gZ2VuZV90eXBlCiAgICAgICAgICAgICAgICAgICkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMChwLmFkaiksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC1sMmZjLGwyZmMpLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbHMpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gc2hhcGVzKSArCiAgZmFjZXRfd3JhcCgiY2x1c3RlciIsIG5yb3cgPSAxKSArCiAgeWxhYigiLWxvZzEwKHBhZGopIikgKwogIHRoZW1lX2J3KCkrCiAgZ2d0aXRsZSgiU2lnLiBtYXJrZXIgZ2VuZXMgKHdpdGhvdXQgTVQgYW5kIEhPWCBnZW5lcyIpCgp2b2xwbG90X25vbXQKIyBnZ3Bsb3RseSh2b2xwbG90X25vbXQsIHdpZHRoID0gMTAwMCwgaGVpZ2h0ID0gNjAwKQoKYGBgCgpgYGB7cn0Kdm9scGxvdF9ub210ICsKICAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBpZmVsc2UoZ2VuZV90eXBlID09ICducycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHZW5lLm5hbWUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpCmBgYAoKCiMjIyBObyBNTiBERSBnZW5lcwoKQ2x1c3RlciAzMCAoQ29uc2lzdGluZyBvZiAxNjEgQjEwIHZzIDEzIEwxMCBjZWxscykgc2hvd3Mgbm8gTU4gcmVsYXRlZCBtYXJrZXJzLiBTZWVtaW5nbHksIHRob3NlIDEzIGNlbGxzIGFyZSBpbmRlZWQgbW90b3IgbmV1cm9ucy4gVGhpcyBpcyBzdXBwb3J0ZWQgYnkgdGhlIGZhY3Qgb2YgdGhlaXIgZXhwcmVzc2lvbiBvZiBUVUJCMywgRk9YUDEsIGFuZCBTTEMxOEEzLgoKYGBge3J9CiMgTW90b3IgbmV1cm9uIGNsdXN0ZXIKbW4uc2UgPC0gc3Vic2V0KHggPSBteS5zZSwgaWRlbnRzID0gMzApCm1uLnNlJHNhbXBsZSA8LSBzdHJfZXh0cmFjdChtbi5zZSRvcmlnLmlkZW50LCAiY3RybHxsdW1iIikKCm1uLnNlQGFjdGl2ZS5hc3NheSA8LSAiaW50ZWdyYXRlZCIKCm1uX21hcmtlcnMgPC0gZ25hbWVzW2dyZXBsKCJUVUJCM3xGT1hQMXxTTEMxOEEzIiwgZ25hbWVzJEdlbmUubmFtZSksXQptbl9tYXJrZXJzCgpWbG5QbG90KG1uLnNlLCBncm91cC5ieSA9ICJzYW1wbGUiLCBtbl9tYXJrZXJzJEdlbmUuc3RhYmxlLklELCBjb2xzID0gYygiZGFya2dyZXkiLCAiIzQxOWM3MyIpKQpgYGAKCiMjIExvdyBEQSBjbHVzdGVycyBmcm9tIG1pbG9SCgpJbiBjb250cmFzdCB0byB0aGUgY2x1c3RlcnMgYWJvdmUsIHdlIG5vdyBzZWxlY3QgY2x1c3RlcnMgMTcsIDE4LCBhbmQgMTkuIFRoZSBzaG93IGEgdmVyeSBsb3cgYW1vdW50IG9mIERBIG5laWdoYm91cmhvb2RzLCBhcmUgb2Ygc2ltaWxhciBzaXplIGFuZCByZXByZXNlbnQgbmV1cm9uYWwsIE1GT0wsIGFuZCBOUEMgcG9wdWxhdGlvbnMuCgpgYGB7cn0KIyB2ZWN0b3Igb2YgTUZPTCBjbHVzdGVycwpsb3dfY2x1c3RlcnMgPC0gYygxNywgMTgsIDE5KQoKbG93X2x1bWJfbWFya2VycyA8LSBmaWx0ZXIobHVtYl9tYXJrZXJzLCBjbHVzdF9pZCAlaW4lIGxvd19jbHVzdGVycykKbG93X2x1bWJfbnVtYmVycyA8LSBmaWx0ZXIobHVtYl9udW1iZXJzLCBjbHVzdF9pZCAlaW4lIGxvd19jbHVzdGVycykKbG93X2x1bWJfY29tcG9zaXRpb24gPC0gZmlsdGVyKGx1bWJfY29tcG9zaXRpb24sIGNsdXN0X2lkICVpbiUgbG93X2NsdXN0ZXJzKQpgYGAKCgojIyMgQmFycGxvdHMKCkJhcnBsb3RzIHNob3dpbmcgbnVtYmVyIG9mIGNlbGxzIGZyb20gQjEwIG9yIEwxMCwgYW5kIHRoZSBjb250cmlidXRpb25zIGZyb20gdGhlIGluZGl2aWR1YWwgQjEwaW50IGFuZCBMMTBpbnQgY2x1c3RlcnM6CgpgYGB7ciBiYXJwbG90cy1MMTAtTUZPTH0KZ2dwbG90KGRhdGEgPSBsb3dfbHVtYl9udW1iZXJzLCBhZXMoeCA9IFZhcjEsIHkgPSBGcmVxLCBncm91cCA9IGNsdXN0ZXIsIGxhYmVsID0gRnJlcSkpICsKICBnZW9tX2NvbCgpICsKICBmYWNldF93cmFwKCJjbHVzdGVyIiwgbnJvdyA9IDEpICsKICBnZW9tX3RleHQobnVkZ2VfeSA9IDEwKSArCiAgZ2d0aXRsZSgiQ2x1c3RlciBjb21wb3NpdGlvbiBieSBzYW1wbGUgKG5DZWxscykiKQoKYGBgCgpgYGB7cn0KdG9wbG90IDwtIGxvd19sdW1iX2NvbXBvc2l0aW9uICU+JSAKICBtdXRhdGUoYW5ub3Rfc2FtcGxlID0gc3RyX2V4dHJhY3QoYW5ub3Rfc2FtcGxlLCAiXFxkezEsMn1fLnsxfSg/PXRybHx1bWIpIikpICU+JSAKICBtdXRhdGUoYW5ub3Rfc2FtcGxlID0gZmFjdG9yKGFubm90X3NhbXBsZSkpICU+JSAKICBncm91cF9ieShzYW1wbGUsIGNsdXN0ZXIpICU+JQogIGNvdW50KGFubm90X3NhbXBsZSkgJT4lIAogIG11dGF0ZShsYWJlbF95cG9zID0gY3Vtc3VtKG4pLSAwLjUqbikKCkJMX2xvd19iYXJwbG90IDwtIGdncGxvdChkYXRhPXRvcGxvdCwgYWVzKHg9c2FtcGxlLCB5PW4sIGZpbGw9ZmN0X3Jldihhbm5vdF9zYW1wbGUpKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyh5PWxhYmVsX3lwb3MsIGxhYmVsPWFubm90X3NhbXBsZSksIAogICAgICAgICAgICBjb2xvcj0iYmxhY2siLCBzaXplPTMuNSkgKwogIGZhY2V0X3dyYXAoImNsdXN0ZXIiLCBucm93ID0gMSkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogIGdndGl0bGUoIkZyb20gd2hpY2ggY2x1c3RlcnMgZG8gY2VsbHMgY29tZT8iKQoKQkxfbG93X2JhcnBsb3QKCnBkZigifi9zcGluYWxfY29yZF9wYXBlci9maWd1cmVzL0ZpZ180X0JMMTBpbnRfbG93X0RBX2NsdXN0X2NvbnRyaWJ1dGlvbi5wZGYiKQpCTF9sb3dfYmFycGxvdApkZXYub2ZmKCkKCmBgYAoKIyMjIFZvbGNhbm9wbG90cwoKYGBge3Igdm9scGxvdHMtTDEwX01GT0wsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gNn0KdG9wbG90IDwtIGxvd19sdW1iX21hcmtlcnMgJT4lIAogIG11dGF0ZShnZW5lX3R5cGUgPSBjYXNlX3doZW4oCiAgICBhdmdfbG9nMkZDID49IDAuNSAmIHBfdmFsX2FkaiA8PSAwLjA1IH4gImN0cmwiLAogICAgYXZnX2xvZzJGQyA8PSAtMC41ICYgcF92YWxfYWRqIDw9IDAuMDUgfiAibHVtYiIsCiAgICBUUlVFIH4gIm5zIikKICApCgpjb2xzIDwtIGMoY3RybCA9ICJibGFjayIsCiAgICAgICAgICBsdW1iID0gIiM0MTljNzMiLAogICAgICAgICAgbnMgPSAiZ3JleSIpCgpzaGFwZXMgPC0gYyhjdHJsID0gMjEsCiAgICAgICAgICAgIGx1bWIgPSAyMSwKICAgICAgICAgICAgbnMgPSAyMCkKCnZvbHBsb3QgPC0gZ2dwbG90KGRhdGEgPSB0b3Bsb3QsCiAgICAgICAgICAgICAgICAgIGFlcyh4ID0gYXZnX2xvZzJGQywKICAgICAgICAgICAgICAgICAgICAgIHkgPSAtbG9nMTAocF92YWxfYWRqKSwKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gR2VuZS5uYW1lLAogICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBnZW5lX3R5cGUsCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGdlbmVfdHlwZQogICAgICAgICAgICAgICAgICApKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtbG9nMTAocC5hZGopLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtbDJmYyxsMmZjKSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xzKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IHNoYXBlcykgKwogIHhsaW0oYygtMy41LCAzLjUpKSArCiAgZmFjZXRfd3JhcCgiY2x1c3RlciIsIG5yb3cgPSAxKSArCiAgeWxhYigiLWxvZzEwKHBhZGopIikgKwogIHRoZW1lX2J3KCkrCiAgZ2d0aXRsZSgiU2lnLiBtYXJrZXIgZ2VuZXMiKQoKdm9scGxvdAojIGdncGxvdGx5KHZvbHBsb3QsIHdpZHRoID0gODAwLCBoZWlnaHQgPSA1MDApCgpgYGAKClBsb3RzIHdpdGhvdXQgSE9YIGFuZCBtaXRvY2hvbmRyaWFsIGdlbmVzOgoKYGBge3IsICBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDZ9CiMgZmlsdGVyIG91dCBIT1ggYW5kIE1UIGdlbmVzCnRvcGxvdF9ub210IDwtIHRvcGxvdCAlPiUgCiAgZmlsdGVyKCFncmVwbCgiXkhPWCIsIEdlbmUubmFtZSkpICU+JSAKICBmaWx0ZXIoIUdlbmUuc3RhYmxlLklEICVpbiUgbXQpCgp2b2xwbG90X25vbXQgPC0gZ2dwbG90KGRhdGEgPSB0b3Bsb3Rfbm9tdCwKICAgICAgICAgICAgICAgICAgYWVzKHggPSBhdmdfbG9nMkZDLAogICAgICAgICAgICAgICAgICAgICAgeSA9IC1sb2cxMChwX3ZhbF9hZGopLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBHZW5lLm5hbWUsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGdlbmVfdHlwZSwKICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gZ2VuZV90eXBlCiAgICAgICAgICAgICAgICAgICkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMChwLmFkaiksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC1sMmZjLGwyZmMpLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbHMpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gc2hhcGVzKSArCiAgeGxpbShjKC0xLjUsIDEuNSkpICsKICBmYWNldF93cmFwKCJjbHVzdGVyIiwgbnJvdyA9IDEsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgeWxhYigiLWxvZzEwKHBhZGopIikgKwogIHRoZW1lX2J3KCkrCiAgZ2d0aXRsZSgiU2lnLiBtYXJrZXIgZ2VuZXMgKHdpdGhvdXQgTVQgYW5kIEhPWCBnZW5lcykiKQoKdm9scGxvdF9ub210CiMgZ2dwbG90bHkodm9scGxvdF9ub210LCB3aWR0aCA9IDgwMCwgaGVpZ2h0ID0gNTAwKQoKYGBgCgpgYGB7cn0KcDEgPC0gdm9scGxvdCArCiAgICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gaWZlbHNlKGdlbmVfdHlwZSA9PSAnbnMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR2VuZS5uYW1lKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKQoKcDIgPC0gdm9scGxvdF9ub210ICsKICAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBpZmVsc2UoZ2VuZV90eXBlID09ICducycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHZW5lLm5hbWUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpCgpwMQpwMgoKcGRmKCJ+L3NwaW5hbF9jb3JkX3BhcGVyL2ZpZ3VyZXMvRmlnXzRfQkwxMGludF9sb3dfREFfdm9scGxvdHMucGRmIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQpwMQpwMgpkZXYub2ZmKCkKCmBgYAoKIyBCMTAtUDEwLWludAoKYGBge3IgQjEwLVAxMC1pbnR9CiMgc2V1cmF0IG9iamVjdApteS5zZSA8LSByZWFkUkRTKCJ+L3NwaW5hbF9jb3JkX3BhcGVyL2RhdGEvR2dfY3RybF9wb2x5X2ludF9zZXVyYXRfMjUwNzIzLnJkcyIpCiMgY2x1c3RlciBsYWJlbHMgZnJvbSBCMTBpbnQgYW5kIEwxMGludApjdHJsX3BvbHlfaW50X2NvbWJpbmVkX2xhYmVscyA8LSByZWFkUkRTKCJ+L3NwaW5hbF9jb3JkX3BhcGVyL2Fubm90YXRpb25zL2N0cmxfcG9seV9pbnRfY29tYmluZWRfbGFiZWxzLnJkcyIpCgppZGVudGljYWwoY29sbmFtZXMobXkuc2UpLCByb3duYW1lcyhjdHJsX3BvbHlfaW50X2NvbWJpbmVkX2xhYmVscykpCm15LnNlJGFubm90X3NhbXBsZSAgPC0gY3RybF9wb2x5X2ludF9jb21iaW5lZF9sYWJlbHMkYW5ub3Rfc2FtcGxlCgpteS5zZUBhY3RpdmUuYXNzYXkgPC0gIlJOQSIKCmBgYAoKIyMgaW50cmEgY2x1c3RlciBERSBhbmFseXNpcwoKV2UgZG8gREUgYW5hbHlzaXMgcGVyIGNsdXN0ZXIsIGNvbnRyYXN0aW5nIEIxMCBhbmQgUDEwIHNhbXBsZXM6CgpgYGB7ciBpbnRyYS1jbHVzdGVyLURFLVAxMCwgZXZhbD1GQUxTRX0KbWFya2VycyA8LSBsaXN0KCkKbnVtYmVycyA8LSBsaXN0KCkKY29tcG9zaXRpb24gPC0gbGlzdCgpCgpmb3IgKGkgaW4gc2VxKGxldmVscyhJZGVudHMobXkuc2UpKSkpIHsKICAjIHN1YnNldCBmb3IgaW5kaXZpZHVhbCBjbHVzdGVycwogIG1uLnNlIDwtIHN1YnNldCh4ID0gbXkuc2UsIGlkZW50cyA9IGxldmVscyhJZGVudHMobXkuc2UpKVtpXSkKICBtbi5zZSRzYW1wbGUgPC0gc3RyX2V4dHJhY3QobW4uc2Ukb3JpZy5pZGVudCwgImN0cmx8cG9seSIpCiAgCiAgY29tcG9zaXRpb25bW2ldXSA8LSBtbi5zZVtbXV0gJT4lIAogICAgc2VsZWN0KHNhbXBsZSwgYW5ub3Rfc2FtcGxlKQogIAogIElkZW50cyhtbi5zZSkgPC0gInNhbXBsZSIKICAKICB0bXBfbWFya2VycyA8LSBGaW5kTWFya2Vycyhtbi5zZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZGVudC4xID0gImN0cmwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5wY3QgPSAwLjI1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAgMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhdGVudC52YXJzID0gYygiQ0MuRGlmZmVyZW5jZS5zZXVyYXQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAiTUFTVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlJOQSIpCiAgIyBjZWxsIG51bWJlcnMgcGVyIHNhbXBsZQogIG51bWJlcnNbW2ldXSA8LSBkYXRhLmZyYW1lKHRhYmxlKG1uLnNlJHNhbXBsZSkpCiAgCiAgdG1wX21hcmtlcnMgPC0gdG1wX21hcmtlcnMgJT4lCiAgICByb3duYW1lc190b19jb2x1bW4oIkdlbmUuc3RhYmxlLklEIikgJT4lIAogICAgbGVmdF9qb2luKGduYW1lcykKICAKICAKICBtYXJrZXJzW1tpXV0gPC0gdG1wX21hcmtlcnMKfQoKbmFtZXMobWFya2VycykgPC0gcGFzdGUwKCJjbC0iLCBsZXZlbHMoSWRlbnRzKG15LnNlKSkpCm5hbWVzKG51bWJlcnMpIDwtIHBhc3RlMCgiY2wtIiwgbGV2ZWxzKElkZW50cyhteS5zZSkpKQpuYW1lcyhjb21wb3NpdGlvbikgPC0gcGFzdGUwKCJjbC0iLCBsZXZlbHMoSWRlbnRzKG15LnNlKSkpCgojIGJpbmQgbGlzdHMgaW50byBkYXRhIGZyYW1lcwpwb2x5X21hcmtlcnMgPC0gYmluZF9yb3dzKG1hcmtlcnMsIC5pZCA9ICJjbHVzdGVyIikgJT4lIAogIG11dGF0ZShjbHVzdGVyID0gZmFjdG9yKGNsdXN0ZXIsIGxldmVscyA9IHBhc3RlMCgiY2wtIiwgbGV2ZWxzKElkZW50cyhteS5zZSkpKSkpCnBvbHlfbnVtYmVycyA8LSBiaW5kX3Jvd3MobnVtYmVycywgLmlkID0gImNsdXN0ZXIiKSAlPiUgCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoY2x1c3RlciwgbGV2ZWxzID0gcGFzdGUwKCJjbC0iLCBsZXZlbHMoSWRlbnRzKG15LnNlKSkpKSkKcG9seV9jb21wb3NpdGlvbiA8LSBiaW5kX3Jvd3MoY29tcG9zaXRpb24sIC5pZCA9ICJjbHVzdGVyIikgJT4lIAogIG11dGF0ZShjbHVzdGVyID0gZmFjdG9yKGNsdXN0ZXIsIGxldmVscyA9IHBhc3RlMCgiY2wtIiwgbGV2ZWxzKElkZW50cyhteS5zZSkpKSkpCgpzYXZlUkRTKHBvbHlfbWFya2VycywgIn4vc3BpbmFsX2NvcmRfcGFwZXIvZGF0YS9HZ19jdHJsX3BvbHlfaW50X21hcmtlcnMucmRzIikKc2F2ZVJEUyhwb2x5X251bWJlcnMsICJ+L3NwaW5hbF9jb3JkX3BhcGVyL2RhdGEvR2dfY3RybF9wb2x5X2ludF9udW1iZXJzLnJkcyIpCnNhdmVSRFMocG9seV9jb21wb3NpdGlvbiwgIn4vc3BpbmFsX2NvcmRfcGFwZXIvZGF0YS9HZ19jdHJsX3BvbHlfaW50X2NvbXBvc2l0aW9uLnJkcyIpCmBgYAoKCmBgYHtyfQojIGxvYWQgdGhlIERFIGRhdGEKcG9seV9tYXJrZXJzIDwtIHJlYWRSRFMoIn4vc3BpbmFsX2NvcmRfcGFwZXIvZGF0YS9HZ19jdHJsX3BvbHlfaW50X21hcmtlcnMucmRzIikgJT4lIAogIG11dGF0ZShjbHVzdF9pZCA9IHN0cl9yZW1vdmUoY2x1c3RlciwgIl5jbC0iKSkKcG9seV9udW1iZXJzIDwtIHJlYWRSRFMoIn4vc3BpbmFsX2NvcmRfcGFwZXIvZGF0YS9HZ19jdHJsX3BvbHlfaW50X251bWJlcnMucmRzIikgJT4lIAogIG11dGF0ZShjbHVzdF9pZCA9IHN0cl9yZW1vdmUoY2x1c3RlciwgIl5jbC0iKSkKcG9seV9jb21wb3NpdGlvbiA8LSByZWFkUkRTKCJ+L3NwaW5hbF9jb3JkX3BhcGVyL2RhdGEvR2dfY3RybF9wb2x5X2ludF9jb21wb3NpdGlvbi5yZHMiKSAlPiUgCiAgbXV0YXRlKGNsdXN0X2lkID0gc3RyX3JlbW92ZShjbHVzdGVyLCAiXmNsLSIpKQpgYGAKClBsb3QgdGhlIGNsdXN0ZXIgY29tcG9zaXRpb25zIGFuZCB0aGUgbnVtYmVyIG9mIG1hcmtlciBnZW5lcy4KCmBgYHtyfQoKRGltUGxvdChteS5zZSwgbGFiZWwgPSBUUlVFLCByZWR1Y3Rpb24gPSAidHNuZSIpCgpnZ3Bsb3QoZGF0YSA9IHBvbHlfbnVtYmVycywgYWVzKHggPSBWYXIxLCB5ID0gRnJlcSwgZ3JvdXAgPSBjbHVzdGVyLCBsYWJlbCA9IEZyZXEpKSArCiAgZ2VvbV9jb2woKSArCiAgZmFjZXRfd3JhcCgiY2x1c3RlciIsIG5yb3cgPSAzKSArCiAgZ2VvbV90ZXh0KG51ZGdlX3kgPSA1MCwgc2l6ZSA9IDMpICsKICBnZ3RpdGxlKCJDbHVzdGVyIGNvbXBvc2l0aW9uIGJ5IHNhbXBsZSAobkNlbGxzKSIpCgpnZ3Bsb3QoZGF0YSA9IHBvbHlfbWFya2VycyAlPiUgZmlsdGVyKHBfdmFsX2FkaiA8IDAuMDUgJiBhdmdfbG9nMkZDID4gMC41KSwgYWVzKHggPSBjbHVzdGVyLCBncm91cCA9IGNsdXN0ZXIpKSArCiAgZ2VvbV9iYXIoKSArCiAgZmFjZXRfd3JhcCgiY2x1c3RlciIsIG5yb3cgPSAzLHNjYWxlcyA9ICJmcmVlX3giKSArCiAgZ2d0aXRsZSgiTnVtYmVyIG9mIHNpZy4gREUgZ2VuZXMiKQoKYGBgCgojIyBGaWc1IGNhbmRpZGF0ZXMKCmBgYHtyfQojIHZlY3RvciBvZiBuZXVyb25hbCBjbHVzdGVycwpmaWc1X2NsdXN0ZXJzIDwtIGMoNSwxMSwxOCwyMiwyNSkKCmZpZzVfcG9seV9tYXJrZXJzIDwtIGZpbHRlcihwb2x5X21hcmtlcnMsIGNsdXN0X2lkICVpbiUgZmlnNV9jbHVzdGVycykKZmlnNV9wb2x5X251bWJlcnMgPC0gZmlsdGVyKHBvbHlfbnVtYmVycywgY2x1c3RfaWQgJWluJSBmaWc1X2NsdXN0ZXJzKQpmaWc1X3BvbHlfY29tcG9zaXRpb24gPC0gZmlsdGVyKHBvbHlfY29tcG9zaXRpb24sIGNsdXN0X2lkICVpbiUgZmlnNV9jbHVzdGVycykKYGBgCgoKCiMjIyBCYXJwbG90cwoKQmFycGxvdHMgc2hvd2luZyBudW1iZXIgb2YgY2VsbHMgZnJvbSBCMTAgb3IgUDEwLCBhbmQgdGhlIGNvbnRyaWJ1dGlvbnMgZnJvbSB0aGUgaW5kaXZpZHVhbCBCMTBpbnQgYW5kIFAxMGludCBjbHVzdGVyczoKCmBgYHtyIGJhcnBsb3RzLVAxMH0KZ2dwbG90KGRhdGEgPSBmaWc1X3BvbHlfbnVtYmVycywgYWVzKHggPSBWYXIxLCB5ID0gRnJlcSwgZ3JvdXAgPSBjbHVzdGVyLCBsYWJlbCA9IEZyZXEpKSArCiAgZ2VvbV9jb2woKSArCiAgZmFjZXRfd3JhcCgiY2x1c3RlciIsIG5yb3cgPSAxKSArCiAgZ2VvbV90ZXh0KG51ZGdlX3kgPSAxMCkgKwogIGdndGl0bGUoIkNsdXN0ZXIgY29tcG9zaXRpb24gYnkgc2FtcGxlIChuQ2VsbHMpIikKYGBgCgpgYGB7cn0KCnRvcGxvdCA8LSBmaWc1X3BvbHlfY29tcG9zaXRpb24gJT4lIAogIG11dGF0ZShhbm5vdF9zYW1wbGUgPSBzdHJfZXh0cmFjdChhbm5vdF9zYW1wbGUsICJcXGR7MSwyfV8uezF9KD89dHJsfG9seSkiKSkgJT4lIAogIG11dGF0ZShhbm5vdF9zYW1wbGUgPSBmYWN0b3IoYW5ub3Rfc2FtcGxlKSkgJT4lIAogIGdyb3VwX2J5KHNhbXBsZSwgY2x1c3RlcikgJT4lCiAgY291bnQoYW5ub3Rfc2FtcGxlKSAlPiUgCiAgbXV0YXRlKGxhYmVsX3lwb3MgPSBjdW1zdW0obiktIDAuNSpuKQoKQlBfbmV1cm9uX2JhcnBsb3QgPC0gZ2dwbG90KGRhdGE9dG9wbG90LCBhZXMoeD1zYW1wbGUsIHk9biwgZmlsbD1mY3RfcmV2KGFubm90X3NhbXBsZSkpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX3RleHQoYWVzKHk9bGFiZWxfeXBvcywgbGFiZWw9YW5ub3Rfc2FtcGxlKSwgCiAgICAgICAgICAgIGNvbG9yPSJibGFjayIsIHNpemU9My41KSArCiAgZmFjZXRfd3JhcCgiY2x1c3RlciIsIG5yb3cgPSAxKSArIAogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogIGdndGl0bGUoIkZyb20gd2hpY2ggY2x1c3RlcnMgZG8gY2VsbHMgY29tZT8iKQoKQlBfbmV1cm9uX2JhcnBsb3QgCmBgYAoKCiMjIyBWb2xjYW5vcGxvdHMKCmBgYHtyIHZvbHBsb3RzLVAxMCwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA2fQp0b3Bsb3QgPC0gZmlnNV9wb2x5X21hcmtlcnMgJT4lIAogIG11dGF0ZShnZW5lX3R5cGUgPSBjYXNlX3doZW4oCiAgICBhdmdfbG9nMkZDID49IDAuNSAmIHBfdmFsX2FkaiA8PSAwLjA1IH4gImN0cmwiLAogICAgYXZnX2xvZzJGQyA8PSAtMC41ICYgcF92YWxfYWRqIDw9IDAuMDUgfiAicG9seSIsCiAgICBUUlVFIH4gIm5zIikKICApCgpjb2xzIDwtIGMoY3RybCA9ICJibGFjayIsCiAgICAgICAgICBwb2x5ID0gImdvbGRlbnJvZDMiLAogICAgICAgICAgbnMgPSAiZ3JleSIpCgpzaGFwZXMgPC0gYyhjdHJsID0gMjEsCiAgICAgICAgICAgIHBvbHkgPSAyMSwKICAgICAgICAgICAgbnMgPSAyMCkKCgp2b2xwbG90IDwtIGdncGxvdChkYXRhID0gdG9wbG90LAogICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gYXZnX2xvZzJGQywKICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IC1sb2cxMChwX3ZhbF9hZGopLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IEdlbmUubmFtZSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gZ2VuZV90eXBlLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBnZW5lX3R5cGUKICAgICAgICAgICAgICAgICAgICAgICApKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtbG9nMTAocC5hZGopLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtbDJmYyxsMmZjKSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xzKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IHNoYXBlcykgKwogIGZhY2V0X3dyYXAoImNsdXN0ZXIiLCBucm93ID0gMiwgc2NhbGVzID0gImZyZWUiKSArCiAgeWxhYigiLWxvZzEwKHBhZGopIikgKwogIHRoZW1lX2J3KCkrCiAgZ2d0aXRsZSgiU2lnLiBtYXJrZXIgZ2VuZXMiKQoKIyBnZ3Bsb3RseSh2b2xwbG90LCB3aWR0aCA9IDEwMDAsIGhlaWdodCA9IDYwMCkKYGBgCgoKUGxvdHMgd2l0aG91dCBtaXRvY2hvbmRyaWFsIGdlbmVzOgoKYGBge3IgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA2fQp0b3Bsb3Rfbm9tdCA8LSB0b3Bsb3QgJT4lIAogIGZpbHRlcighR2VuZS5zdGFibGUuSUQgJWluJSBtdCkKCnZvbHBsb3Rfbm9tdCA8LSBnZ3Bsb3QoZGF0YSA9IHRvcGxvdF9ub210LAogICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gYXZnX2xvZzJGQywKICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IC1sb2cxMChwX3ZhbF9hZGopLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IEdlbmUubmFtZSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gZ2VuZV90eXBlLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBnZW5lX3R5cGUKICAgICAgICAgICAgICAgICAgICAgICApKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtbG9nMTAocC5hZGopLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtbDJmYyxsMmZjKSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xzKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IHNoYXBlcykgKwogIGZhY2V0X3dyYXAoImNsdXN0ZXIiLCBucm93ID0gMSkgKwogIHlsYWIoIi1sb2cxMChwYWRqKSIpICsKICB4bGltKGMoLTMsMykpKwogIHRoZW1lX2J3KCkrCiAgZ2d0aXRsZSgiU2lnLiBtYXJrZXIgZ2VuZXMgKHdpdGhvdXQgTVQgYW5kIEhPWCBnZW5lcyIpCgojIGdncGxvdGx5KHZvbHBsb3Rfbm9tdCkKYGBgCgpgYGB7cn0KcGZpZzUgPC0gdm9scGxvdF9ub210ICArCiAgICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gaWZlbHNlKGdlbmVfdHlwZSA9PSAnbnMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR2VuZS5uYW1lKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKQoKcGRmKCJ+L3NwaW5hbF9jb3JkX3BhcGVyL2ZpZ3VyZXMvRmlnXzVfQlBvbHkxMGludF92b2xwbG90cy5wZGYiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA0KQpwZmlnNQpkZXYub2ZmKCkKYGBgCgpgYGB7cn0KIyBEYXRlIGFuZCB0aW1lIG9mIFJlbmRlcmluZwpTeXMudGltZSgpCgpzZXNzaW9uSW5mbygpCmBgYA==